use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;

/// Main configuration structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Config {
    pub node: NodeConfig,
    pub cluster: ClusterConfig,
    pub raft: RaftConfig,
    pub storage: StorageConfig,
    pub network: NetworkConfig,
    pub api: ApiConfig,
    pub health_check: HealthCheckConfig,
    pub failover: FailoverConfig,
    pub monitoring: MonitoringConfig,
    pub logging: LoggingConfig,
    pub performance: PerformanceConfig,
    pub security: SecurityConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NodeConfig {
    pub id: u64,
    pub bind_addr: String,
    pub data_dir: PathBuf,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ClusterConfig {
    pub name: String,
    pub peers: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RaftConfig {
    pub election_timeout_ms: u64,
    pub heartbeat_interval_ms: u64,
    pub snapshot_threshold: u64,
    pub max_append_entries: u64,
    pub install_snapshot_chunk_size: u64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StorageConfig {
    #[serde(rename = "type")]
    pub storage_type: String,
    pub duckdb: Option<DuckDbConfig>,
    // Optional other backends (placeholders for now so config deserialization does not fail)
    pub rocksdb: Option<RocksDbConfig>,
    pub mysql: Option<MySqlConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DuckDbConfig {
    pub path: String,
    pub max_connections: u32,
    pub connection_timeout: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RocksDbConfig {
    pub path: String,
    #[serde(default)]
    pub max_open_files: u32,
    #[serde(default)]
    pub write_buffer_size: u64,
    #[serde(default)]
    pub max_write_buffer_number: u32,
    #[serde(default)]
    pub compression: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MySqlConfig {
    pub url: String,
    #[serde(default)]
    pub max_connections: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetworkConfig {
    pub listen_addr: String,
    pub connect_timeout: String,
    pub request_timeout: String,
    pub max_connections: u32,
    pub tls: TlsConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
    pub enabled: bool,
    pub cert_file: String,
    pub key_file: String,
    pub ca_file: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApiConfig {
    pub enabled: bool,
    pub bind_addr: String,
    pub cors: CorsConfig,
    pub auth: AuthConfig,
    pub rate_limit: RateLimitConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CorsConfig {
    pub enabled: bool,
    pub origins: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthConfig {
    pub enabled: bool,
    pub jwt_secret: String,
    pub api_keys: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RateLimitConfig {
    pub enabled: bool,
    pub requests_per_minute: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheckConfig {
    pub interval: String,
    pub timeout: String,
    pub failure_threshold: u32,
    pub recovery_threshold: u32,
    pub checks: Vec<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct FailoverConfig {
    pub enabled: bool,
    pub timeout: String,
    pub auto_failover: bool,
    pub max_retries: u32,
    pub retry_interval: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MonitoringConfig {
    pub prometheus: PrometheusConfig,
    pub tracing: TracingConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PrometheusConfig {
    pub enabled: bool,
    pub bind_addr: String,
    pub path: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TracingConfig {
    pub enabled: bool,
    pub endpoint: String,
    pub service_name: String,
    pub sample_rate: f32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LoggingConfig {
    pub level: String,
    pub format: String,
    pub output: String,
    pub file: LogFileConfig,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LogFileConfig {
    pub path: String,
    pub max_size: String,
    pub max_files: u32,
    pub compress: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceConfig {
    pub worker_threads: usize,
    pub max_blocking_threads: usize,
    pub thread_stack_size: String,
    pub tick_budget: u32,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SecurityConfig {
    pub encryption_key: String,
    pub audit_log: bool,
    pub allowed_ips: Vec<String>,
}

impl Default for Config {
    fn default() -> Self {
        // 默认配置: 为了方便本地开发及单节点快速启动，这里提供一套保守/最小可运行的默认值。
        // 生产环境应使用外部配置文件并调用 `Config::from_file` 载入，再经 `validate()` 校验。
        Self {
            node: NodeConfig {
                id: 1,
                bind_addr: "127.0.0.1:8001".to_string(),
                data_dir: PathBuf::from("./data"),
            },
            cluster: ClusterConfig {
                name: "default-cluster".to_string(),
                peers: vec!["127.0.0.1:8001".to_string()],
            },
            raft: RaftConfig {
                election_timeout_ms: 150,
                heartbeat_interval_ms: 50,
                snapshot_threshold: 10000,
                max_append_entries: 1000,
                install_snapshot_chunk_size: 4096,
            },
            storage: StorageConfig {
                // default to an in-memory like backend (treated as memory by cluster manager)
                storage_type: "memory".to_string(),
                duckdb: None,
                rocksdb: None,
                mysql: None,
            },
            network: NetworkConfig {
                listen_addr: "0.0.0.0:8001".to_string(),
                connect_timeout: "5s".to_string(),
                request_timeout: "10s".to_string(),
                max_connections: 1000,
                tls: TlsConfig {
                    enabled: false,
                    cert_file: String::new(),
                    key_file: String::new(),
                    ca_file: String::new(),
                },
            },
            api: ApiConfig {
                enabled: true,
                bind_addr: "0.0.0.0:8080".to_string(),
                cors: CorsConfig {
                    enabled: true,
                    origins: vec!["*".to_string()],
                },
                auth: AuthConfig {
                    enabled: false,
                    jwt_secret: "your-secret-key".to_string(),
                    api_keys: vec![],
                },
                rate_limit: RateLimitConfig {
                    enabled: true,
                    requests_per_minute: 1000,
                },
            },
            health_check: HealthCheckConfig {
                interval: "10s".to_string(),
                timeout: "5s".to_string(),
                failure_threshold: 3,
                recovery_threshold: 2,
                checks: vec!["connectivity".to_string(), "resource_usage".to_string()],
            },
            failover: FailoverConfig {
                enabled: true,
                timeout: "30s".to_string(),
                auto_failover: true,
                max_retries: 3,
                retry_interval: "5s".to_string(),
            },
            monitoring: MonitoringConfig {
                prometheus: PrometheusConfig {
                    enabled: true,
                    bind_addr: "0.0.0.0:9090".to_string(),
                    path: "/metrics".to_string(),
                },
                tracing: TracingConfig {
                    enabled: false,
                    endpoint: "http://localhost:14268/api/traces".to_string(),
                    service_name: "cluster-node-manager".to_string(),
                    sample_rate: 0.1,
                },
            },
            logging: LoggingConfig {
                level: "info".to_string(),
                format: "json".to_string(),
                output: "stdout".to_string(),
                file: LogFileConfig {
                    path: "./logs/cluster-manager.log".to_string(),
                    max_size: "100MB".to_string(),
                    max_files: 10,
                    compress: true,
                },
            },
            performance: PerformanceConfig {
                worker_threads: 0,
                max_blocking_threads: 512,
                thread_stack_size: "2MB".to_string(),
                tick_budget: 1000,
            },
            security: SecurityConfig {
                encryption_key: "your-encryption-key".to_string(),
                audit_log: false,
                allowed_ips: vec!["127.0.0.1".to_string(), "192.168.0.0/16".to_string()],
            },
        }
    }
}

impl Config {
    /// 从 YAML 配置文件读取配置并反序列化为 `Config`
    ///
    /// 参数:
    /// - `path`: 配置文件路径
    ///
    /// 行为:
    /// - 读取文件内容 (`std::fs::read_to_string`)
    /// - 使用 `serde_yaml` 进行反序列化
    ///
    /// 返回:
    /// - Ok(Config)  解析成功
    /// - Err(anyhow::Error)  读取或解析失败（包含 I/O / YAML 语法错误等）
    pub fn from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
        let content = std::fs::read_to_string(path)?;
        let config: Self = serde_yaml::from_str(&content)?;
        Ok(config)
    }

    /// 将当前配置写入指定文件（YAML 格式）
    ///
    /// 参数:
    /// - `path`: 目标文件路径，不存在则创建，存在则覆盖
    ///
    /// 返回:
    /// - Ok(()) 成功
    /// - Err(anyhow::Error) I/O 或序列化失败
    pub fn to_file<P: AsRef<std::path::Path>>(&self, path: P) -> Result<()> {
        let content = serde_yaml::to_string(self)?;
        std::fs::write(path, content)?;
        Ok(())
    }

    /// 校验配置合法性（语义层面）
    ///
    /// 校验规则概述:
    /// 1. `node.id` 不能为 0 （保留/无意义）
    /// 2. `node.bind_addr` 不能为空
    /// 3. `storage.storage_type` 仅允许 memory / duckdb
    /// 4. Raft: 选举超时时间需 >= 2 * 心跳间隔，避免频繁选举抖动
    ///
    /// 返回:
    /// - Ok(()) 全部通过
    /// - Err(anyhow::Error) 首个违反规则的错误说明
    ///
    /// 注意:
    /// - 不进行端口占用/路径存在性检查，交由运行期处理
    pub fn validate(&self) -> Result<()> {
        // Validate node ID
        if self.node.id == 0 {
            return Err(anyhow::anyhow!("Node ID cannot be 0"));
        }

        // Validate bind address
        if self.node.bind_addr.is_empty() {
            return Err(anyhow::anyhow!("Bind address cannot be empty"));
        }

        // Validate storage configuration
        match self.storage.storage_type.as_str() {
            "duckdb" => {}
            "memory" => {}
            _ => {
                return Err(anyhow::anyhow!(
                    "Invalid storage type: {}",
                    self.storage.storage_type
                ));
            }
        }

        // Validate Raft configuration
        if self.raft.election_timeout_ms < self.raft.heartbeat_interval_ms * 2 {
            return Err(anyhow::anyhow!(
                "Election timeout must be at least twice the heartbeat interval"
            ));
        }

        Ok(())
    }

    /// 从环境变量合并/覆盖关键配置项
    ///
    /// 支持的环境变量:
    /// - CNM_NODE_ID -> node.id
    /// - CNM_NODE_BIND_ADDR -> node.bind_addr
    /// - CNM_LOGGING_LEVEL -> logging.level
    /// - CNM_STORAGE_TYPE -> storage.storage_type
    ///
    /// 行为:
    /// - 若变量存在并能正确解析（如 ID 可解析为 u64），则覆盖对应字段
    /// - 若解析失败会返回错误（例如 ID 不是数值）
    /// - 无副作用: 未设置的变量不影响当前配置
    ///
    /// 使用场景:
    /// - 容器化部署中通过环境变量快速调整参数
    /// - CI / 本地脚本覆盖默认值
    pub fn merge_env(&mut self) -> Result<()> {
        if let Ok(node_id) = std::env::var("CNM_NODE_ID") {
            self.node.id = node_id.parse()?;
        }

        if let Ok(bind_addr) = std::env::var("CNM_NODE_BIND_ADDR") {
            self.node.bind_addr = bind_addr;
        }

        if let Ok(log_level) = std::env::var("CNM_LOGGING_LEVEL") {
            self.logging.level = log_level;
        }

        if let Ok(storage_type) = std::env::var("CNM_STORAGE_TYPE") {
            self.storage.storage_type = storage_type;
        }

        Ok(())
    }
}
